package zone

import (
	"context"
	"github.com/Unixeno/TheMoon/moon/zone/registry"
	"github.com/Unixeno/islands/pb"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

const (
	pullIndexDomain = "https://index.docker.io"
)

func (d *deployer) imagePull(ctx context.Context, imageName string) error {
	imageTag := "latest"
	if strings.Contains(imageName, ":") {
		imageParts := strings.Split(imageName, ":")
		imageName = imageParts[0]
		imageTag = imageParts[1]
	}
	// official image
	repoName := imageName
	if !strings.Contains(imageName, "/") {
		repoName = "library/" + imageName
	}

	tempDir, err := ioutil.TempDir("", "islandsImage")
	defer os.RemoveAll(tempDir)

	if err != nil {
		return err
	}

	r, err := registry.New(registry.Config{
		Endpoint: pullIndexDomain,
		SavePath: tempDir,
		RepoTag:  imageTag,
		RepoName: repoName,
	})

	if err != nil {
		return err
	}
	logger.Debug("GET REGISTRY TOKEN")
	if err := r.GetToken(); err != nil {
		return err
	}
	digest, err := r.GetManifestList()

	logger.Debug("GET IMAGE MANIFEST")
	manifest, err := r.ReposManifest(digest)
	if err != nil {
		return err
	}

	logger.Debug("GET IMAGE CONFIG")
	configFileName, err := r.RepoGetConfig(manifest)
	if err != nil {
		return err
	}

	for {
		layers := make([]*pb.LayerInfo, len(manifest.Layers))
		for i, layer := range manifest.Layers {
			layers[i] = &pb.LayerInfo{
				Digest:    layer.Digest,
				Size:      int64(layer.Size),
				MediaType: layer.MediaType,
			}
		}
		resp, err := islandsClient.ImportImageWithNeed(ctx, &pb.ImportImageWithNeedReq{
			ConfigFilePath: filepath.Join(tempDir, configFileName),
			Layers:         layers,
			ImageName:      imageName,
			ImageTag:       imageTag,
		})

		if err != nil {
			return err
		}

		if resp.Imported {
			logger.Debug("SUCCESS IMPORT!")
			return nil
		}

		manifestLayers := make([]registry.ManifestLayer, len(resp.Layers))

		for i, layer := range resp.Layers {
			manifestLayers[i] = registry.ManifestLayer{
				Digest:    layer.Digest,
				MediaType: layer.MediaType,
				Size:      int(layer.Size),
			}
		}
		logger.Debug("GET IMAGE LAYERS...")
		_, err = r.RepoGetLayers(manifestLayers)

		if err != nil {
			return err
		}
		_, err = islandsClient.ImportLayers(context.Background(), &pb.ImportLayersReq{
			LayersDir: tempDir,
			Layers:    resp.Layers,
		})

		if err != nil {
			return err
		}
	}
}
